package com.learn.sb.sblearnshardingjdbc.strategy;

import com.alibaba.druid.util.StringUtils;
import com.google.common.base.Preconditions;
import com.google.common.collect.BoundType;
import com.google.common.collect.Range;
import io.shardingjdbc.core.api.algorithm.sharding.ListShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.RangeShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.ShardingValue;
import io.shardingjdbc.core.constant.ShardingOperator;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

@Slf4j
public class HintShardingAlgorithm implements io.shardingjdbc.core.api.algorithm.sharding.hint.HintShardingAlgorithm {

	@Override
	public Collection<String> doSharding(Collection<String> availableTargetNames, ShardingValue shardingValue) {
		//		log.debug("shardingValue=" + JacksonHelper.toJSON(shardingValue));
		//		log.debug("availableTargetNames=" + JacksonHelper.toJSON(availableTargetNames));
		List<String> shardingResult = new ArrayList<>();
		availableTargetNames.forEach(targetName -> {
			String suffix = targetName.substring(targetName.lastIndexOf("_") + 1);
			if (StringUtils.isNumber(suffix)) {
				// hint分片算法的ShardingValue有两种具体类型: ListShardingValue和RangeShardingValue，
				// 取决于io.shardingjdbc.core.api.HintManager.addDatabaseShardingValue(String, String, ShardingOperator, Comparable<?>...)的时候,
				// ShardingOperator的类型。见下文。
				ListShardingValue<Integer> tmpSharding = (ListShardingValue<Integer>) shardingValue;
				tmpSharding.getValues().forEach(value -> {
					if (value % 2 == Integer.parseInt(suffix)) {
						shardingResult.add(targetName);
					}
				});

			}
		});
		return shardingResult;
	}

	@SuppressWarnings("unchecked")
	private ShardingValue getShardingValue(final String logicTable, final String shardingColumn, final ShardingOperator operator, final Comparable<?>[] values) {
		Preconditions.checkArgument(null != values && values.length > 0);
		switch (operator) {
			case EQUAL:
			case IN:
				return new ListShardingValue(logicTable, shardingColumn, Arrays.asList(values));
			case BETWEEN:
				return new RangeShardingValue(logicTable, shardingColumn, Range.range(values[0], BoundType.CLOSED, values[1], BoundType.CLOSED));
			default:
				throw new UnsupportedOperationException(operator.getExpression());
		}
	}
}
